﻿using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml;
using SDFL.Helper;
using System.Reflection;

namespace SDFL.Tools.WeatherLib
{
    public class CityInfo
    {
        /// <summary>
        /// City list URL
        /// </summary>
        private const string __Url = "http://www.weather.com.cn/data/listinfo/city{0}.xml";
       
        /// <summary>Cache</summary>
        public static string _CityXmlName = "WeatherCity.Xml";

        /// <summary>City Name</summary>
        public string Name 
        { 
            get; 
            set; 
        }

        /// <summary>City ID</summary>
        public string ID 
        { 
            get; 
            set; 
        }     

        private static CityXmlInfo[] _Citys = null;

        public static CityXmlInfo[] Default
        {
            get
            {
                if (_Citys == null)
                {
                    string CityXmlPath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), @"Tools\WeatherForecast\" + _CityXmlName);                    
                    _Citys = Load(Path.GetFullPath(_CityXmlName));
                }
                return _Citys;
            }
        }
        public override string ToString()
        {
            return this.Name;
        }

        /// <summary>
        /// Get the Province list
        /// </summary>
        /// <returns>Province list</returns>
        public static CityInfo[] GetList()
        {
            return GetList(string.Empty);
        }

        /// <summary>
        /// Get the cityinfo list
        /// 
        /// 1. GetList()
        ///     Get Provinces:   "http://www.weather.com.cn/data/listinfo/city.xml"
        ///            result:   City[] = 01|北京,02|上海,03|天津,04|重庆,05|黑龙江,06|吉林,07|辽宁,08|内蒙古...
        ///      
        /// 2. GetList("01")    
        ///        Get Cities:    "http://www.weather.com.cn/data/listinfo/city01.xml"
        ///            result:   City[] = 0101|北京
        ///      
        /// 3. GetList("0101")  
        ///      Get Counties:    "http://www.weather.com.cn/data/listinfo/city0101.xml"
        ///            result:   City[] = 010101|北京,010102|海淀,010103|朝阳,010104|顺义,010105|怀柔,010106|通州,010107|昌平...
        ///      
        /// 4. GetList("010101")
        ///      Get cityCode:    "http://www.weather.com.cn/data/listinfo/city010101.xml"
        ///            result:   City[] = 010101|101010100
        /// </summary>
        /// <param name="id">ID</param>
        /// <returns>cityInfo List</returns>
        public static CityInfo[] GetList(string id)
        {
            var url = string.Format(__Url, id);
            using (WebClient wc = new WebClient())
            {
                wc.Encoding = Encoding.UTF8;
                string str = wc.DownloadString(url);
                List<CityInfo> citys = new List<CityInfo>();
                var cs = str.Split(',');
                foreach (var c in cs)
                {
                    var carr = c.Split('|');
                    citys.Add(new CityInfo()
                    {
                        ID = carr[0],
                        Name = carr[1]
                    });
                }
                return citys.ToArray();
            }
        }

        /// <summary>
        /// Get city code
        /// </summary>
        /// <param name="name">
        /// City Name
        /// </param>
        /// <returns>city code</returns>
        public static string GetCityCodeByName(string name)
        {
            var city = Default.FirstOrDefault<CityXmlInfo>(c => c.Name == name);
            if (city == null)
            {
                return string.Empty;
            }
            return city.Code;
        }

        private static string GetCityByIp(string regex, string input)
        {
            var reg = new Regex(regex);
            var match = reg.Matches(input);
            if (match.Count == 0)
            {
                return string.Empty;
            }
            return match[match.Count - 1].Result("$1");
        }
        /// <summary>Get City code</summary>
        /// <param name="ipDataPath">IP library path</param>
        /// <param name="ip">IP address</param>
        /// <returns>City code</returns>
        public static string GetCityCodeByIp(string ipDataPath, string ip)
        {
            IPLocation.IPLocation.IPLocate(ipDataPath, ip);
            var country = IPLocation.IPLocation.Country;
            var regex = new Regex("([^市省]+)市");
            var match = regex.Match(country);
            var area = string.Empty;
            var province = string.Empty;
            var city = string.Empty;
            var matCity = Regex.Matches(country, "([^市省]+)市");
            var matArea = Regex.Matches(country, "([^市省区]+)区");
            var matProvince = Regex.Matches(country, "([^省]+)省");
            if (matArea.Count > 0)
            {
                area = matArea[0].Result("$1");
            }
            if (matProvince.Count > 0)
            {
                province = matProvince[0].Result("$1");
            }
            if (matCity.Count > 0)
            {
                city = matCity[matCity.Count - 1].Result("$1");
            }
            var code = string.Empty;
            if (!string.IsNullOrEmpty(area))
            {
                code = GetCityCodeByName(area);
                if (!string.IsNullOrEmpty(code))
                {
                    return code;
                }
            }
            if (!string.IsNullOrEmpty(city))
            {
                code = GetCityCodeByName(city);
                if (!string.IsNullOrEmpty(code))
                {
                    return code;
                }
            }
            if (!string.IsNullOrEmpty(province))
            {
                code = GetCityCodeByName(province);
                if (!string.IsNullOrEmpty(code))
                {
                    return code;
                }
            }
            if (string.IsNullOrEmpty(code))
            {
                code = GetCityCodeByName(country.Substring(0, 2));
                if (!string.IsNullOrEmpty(code))
                {
                    return code;
                }
            }
            return string.Empty;
        }


        public static CityXmlInfo[] Load(string path)
        {
            var cityXmlInfos = new List<CityXmlInfo>();
            var doc = XMLHelper.CreateXmlDocument();
            doc.Load(path);
            var root = doc.DocumentElement;
            foreach (XmlNode node in root.SelectNodes(CityXmlInfo.__City))
            {
                var cityXmlInfo = new CityXmlInfo();
                cityXmlInfo.Read(node);
                cityXmlInfos.Add(cityXmlInfo);
            }
            return cityXmlInfos.ToArray();
        }
        public static void Save(CityXmlInfo[] cityXmlInfos, string path)
        {
            var doc = XMLHelper.CreateXmlDocument();
            var root = XMLHelper.CreateXmlNode(doc, "root");
            doc.AppendChild(root);
            foreach (CityXmlInfo cityXmlInfo in cityXmlInfos)
            {
                root.AppendChild(cityXmlInfo.ToXmlNode(doc));
            }
            var xtr = new XmlTextWriter(path, Encoding.UTF8);
            xtr.Formatting = Formatting.Indented;
            doc.Save(xtr);
        }
    }
}
